package posts

import (
	"community-service/cmd/api/internal/models/model"
	"community-service/cmd/api/internal/svc"
	"community-service/cmd/api/internal/types"
	e "community-service/pkg/errorx"
	"context"
	"fmt"
	user "gitee.com/vzerx/proto-contracts/auth"
	"github.com/zeromicro/go-zero/core/logx"
	"google.golang.org/grpc/codes"
)

type GetPostLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetPostLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetPostLogic {
	return &GetPostLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetPostLogic) GetPost(req *types.PostReq) (*types.PostRsp, error) {

	postQuery := l.svcCtx.DB.WithContext(l.ctx).Model(&model.CsCommunityPost{}).
		Joins("post").
		Joins(fmt.Sprintf("INNER JOIN %s topic ON post.topic_id = topic.id", model.TableNameCsCommunityTopic)).
		Joins(fmt.Sprintf("INNER JOIN %s menu ON menu.id = topic.menu_id", model.TableNameCsCommunityMenu)).
		Joins(fmt.Sprintf("LEFT JOIN %s approve ON approve.post_id = post.id", model.TableNameCsCommunityPostApprove)).
		Joins(fmt.Sprintf("LEFT JOIN %s exp ON exp.id = post.id", model.TableNameCsCommunityPostExperimentMap)).
		Joins(fmt.Sprintf("LEFT JOIN %s comment ON comment.post_id = post.id", model.TableNameCsCommunityPostComment)).
		Joins(fmt.Sprintf("LEFT JOIN %s my_approve ON approve.post_id = post.id AND approve.create_user = %d",
			model.TableNameCsCommunityPostApprove, req.UserProfile.UserId)).
		Where("post.id = ?", req.Id).
		Select(
			"post.id", "post.topic_id", "post.title", "post.content", "post.status",
			"topic.name topic_name", "menu.id menu_id", "menu.name menu_name",
			"post.is_topped", "post.is_selected", "post.is_official",
			"post.view_count", "post.reason", "post.create_user", "post.create_username",
			"IFNULL(COUNT(DISTINCT approve.id), 0) as approve_count",
			"1 owner",
			"CASE WHEN my_approve.id IS NOT NULL THEN 1 END is_approved",
			"IFNULL(COUNT(DISTINCT comment.id), 0) as comment_count",
			"UNIX_TIMESTAMP(post.created_at) as created_at",
			"UNIX_TIMESTAMP(post.updated_at) as updated_at",
			"IFNULL(exp.experiment_id, 0) as experiment_id",
			"IFNULL(exp.experiment_name, '') as experiment_name",
			"IFNULL(exp.course_resource_id, '') as course_resource_id",
			"IFNULL(exp.chapter_ref_id, '') as chapter_ref_id",
		)

	// 临时结构体接收查询结果
	type PostWithExperiment struct {
		types.PostRsp
		MenuName         string `json:"menu_name"`
		TopicName        string `json:"topic_name"`
		ExperimentId     int64  `json:"experiment_id"`
		ExperimentName   string `json:"experiment_name"`
		CourseResourceId string `json:"course_resource_id"`
		ChapterRefId     string `json:"chapter_ref_id"`
	}

	var raw PostWithExperiment
	if err := postQuery.
		Group("post.id").
		Order("post.is_topped DESC, post.is_selected DESC, post.is_official DESC, post.created_at DESC").
		Offset((req.PageNum - 1) * req.PageSize).
		Limit(req.PageSize).
		Find(&raw).Error; err != nil {
		return nil, e.NewGrpcErr(codes.Internal, e.DBError)
	}

	if raw.Id == 0 {
		return nil, e.NewGrpcErr(codes.NotFound, e.PostNotFound)
	}

	resp := &types.PostRsp{
		Id:      raw.Id,
		Title:   raw.Title,
		Content: raw.Content,
		MenuId:  raw.MenuId,
		TopicId: raw.TopicId,
		Status:  raw.Status,
		Reason:  raw.Reason,
		Topic: &types.TopicRsp{
			Id:   raw.TopicId,
			Name: raw.TopicName,
		},
		Menu: &types.MenuRsp{
			Id:   raw.MenuId,
			Name: raw.MenuName,
		},
		IsTopped:       raw.IsTopped,
		IsSelected:     raw.IsSelected,
		IsOfficial:     raw.IsOfficial,
		CreateUser:     raw.CreateUser,
		CreateUsername: raw.CreateUsername,
		CreatedAt:      raw.CreatedAt,
		UpdatedAt:      raw.UpdatedAt,
		Author: &types.AuthorRsp{
			Id:   raw.CreateUser,
			Name: raw.CreateUsername,
		},
		Owner:        raw.Owner,
		IsApproved:   raw.IsApproved,
		ApproveCount: raw.ApproveCount,
		ViewCount:    raw.ViewCount,
		CommentCount: raw.CommentCount,
	}

	if raw.ExperimentId != 0 {
		resp.Experiment = &types.Experiment{
			Id:               raw.ExperimentId,
			Name:             raw.ExperimentName,
			CourseResourceId: raw.CourseResourceId,
			ChapterRefId:     raw.ChapterRefId,
		}
	}

	userInfo, err := l.svcCtx.User.GetUserInfo(l.ctx, &user.UserInfoReq{UserId: raw.CreateUser})
	if err == nil {
		resp.Author = &types.AuthorRsp{
			Id:            userInfo.UserId,
			Name:          userInfo.UserName,
			Sex:           userInfo.Sex,
			Avatar:        userInfo.Avatar,
			CollageName:   userInfo.CollageName,
			SecondOrgName: userInfo.SecOrgName,
			OrgName:       userInfo.OrgName,
		}
	}

	// 更新查看次数
	_ = l.svcCtx.DB.WithContext(l.ctx).Model(&model.CsCommunityPost{}).Where("id = ?", req.Id).Update("view_count", resp.ViewCount+1).Error
	return resp, nil
}
